
#import "AlarmClock.h"
#import "Animator.h"

// Some notes:  there are three alarms.  You can set any or
//		all of the three alarms any way you like.  The alarm only looks at
//		minutes and hours; it ignores seconds...and only has an accuracy
//		of +/- 5 sec. with respect to the system clock, since I only check
//		every ten seconds to see if it's time to go off.  A better way to
//		do this might be to have three timed entries, each set to go off
//		at the right time and call the proper alarm trigger function, but
//		this way works just fine for me.  I really need to implement prefs
//		especially for the "x minutes after launch" alarm:  that would be
//		nice to suggest that you to log off after a certain amount of time.
//		Also, the interface is a bit confusing and very ugly...

@implementation AlarmClock

- appDidInit:sender
{
	int i;
	launchTime = [[DAYTime alloc] initWithCurrentTime];
	fromSet = [[DAYTime alloc] init];
	absolute = [[DAYTime alloc] init];
	fromLaunch = [[DAYTime alloc] init];
	for (i=0; i<3; i++) {
		alarms[i] = [[DAYTime alloc] initWithCurrentTime];
	}
	// set up a timer to call us once every so often.
    animator = [[Animator alloc] initChronon:ALARM_FREQUENCY
    		adaptation:0.0   target:self
    		action:@selector(tick:) autoStart:YES eventMask:0];
	[self doAtSetTime:self];
    return self;
}

- setAlarm:sender
{
	if (alarmType[num] < 0) {
		NXRunAlertPanel(NULL, [strings valueForStringKey:"setTfirst"],
				[strings valueForStringKey:"OK"], NULL, NULL);
		return nil;
	}
	if (alarms[num]) [alarms[num] free];
	switch (num) {
		case 0 : {
			[absolute setMinute:[[timeMatrix findCellWithTag:1] intValue]];
			[absolute setHour:[[timeMatrix findCellWithTag:0] intValue]];
			alarms[0] = [absolute copy];
			break;
		}
		case 1 : {
			[fromSet setMinute:[[timeMatrix findCellWithTag:1] intValue]];
			[fromSet setHour:[[timeMatrix findCellWithTag:0] intValue]];
			alarms[1] = [[DAYTime alloc] initWithCurrentTime];
			// the addTime: method isn't done yet, so I'm using these.
			[alarms[1] addMinutes:[fromSet minute]];
			[alarms[1] addHours:[fromSet hour]];
			break;
		}
		case 2 : {
			[fromLaunch setMinute:[[timeMatrix findCellWithTag:1] intValue]];
			[fromLaunch setHour:[[timeMatrix findCellWithTag:0] intValue]];
			alarms[2] = [launchTime copy];
			[alarms[2] addMinutes:[fromLaunch minute]];
			[alarms[2] addHours:[fromLaunch hour]];
			break;
		}
		default: break;	// should never get here
	}
	alarmOn[num] = YES;
    return self;
}

- tick:sender
{
	int i;
	DAYTime *currentTime = [[DAYTime alloc] initWithCurrentTime];

	for (i=0; i<3; i++) {
		if (alarmOn[i] &&
				([currentTime minute]  == [alarms[i] minute]) &&
				([currentTime hour]  == [alarms[i] hour])) {
			// time to fire off the alarm
			if (((alarmType[i] == ALARM_SOUND_AND_GRAPHIC) ||
					(alarmType[i] == ALARM_GRAPHIC)) && images[i]) {
				// put up a graphic
				NXRect theFrame; NXSize theSize;
				NXPoint aPoint = {0, 0}; Window *aWindow;
				[images[i] getSize:&theSize];
				// really, I should grab the actual screen size here
				// but for now I'm using the standard NeXT screen size
				// (1120x832) since I don't have time to do it right
				NXSetRect(&theFrame, (1120-theSize.width-2)/2,
						(832-theSize.height-21)/2,
						theSize.width, theSize.height);
				aWindow = [[Window alloc] initContent:&theFrame
						style:NX_TITLEDSTYLE backing:NX_RETAINED
						buttonMask:NX_CLOSEBUTTONMASK defer:NO];
				[aWindow setTitle:
						[strings valueForStringKey:"ImageWindowTitle"]];
				[aWindow display];
				[[aWindow contentView] lockFocus];
				[images[i] composite:NX_COPY toPoint:&aPoint];
				[[aWindow contentView] unlockFocus];
				[aWindow makeKeyAndOrderFront:self];
				[NXApp activateSelf:YES];
			}
			if ((alarmType[i] == ALARM_SOUND_AND_GRAPHIC) ||
					(alarmType[i] == ALARM_SOUND)) [sounds[i] play];
			if (alarmType[i] == ALARM_UNIX_COMMAND) {
				// do a UNIX command
				system([commands[i] stringValue]);
			}
			// make sure the alarm doesn't go off more than once
			alarmOn[i] = NO;
		}
	}
    return self;
}

- free
{
	int i;
	for (i=0; i<3; i++) {
		[alarms[i] free];
		[images[i] free];
		[sounds[i] free];
		[commands[i] free];
	}
	[fromSet free];
	[absolute free];
	[fromLaunch free];
	[launchTime free];
	[super free];
	return self;
}

- getSound:sender
{
    const char *const types[] = {"snd", NULL};  

    if ([[OpenPanel new] runModalForTypes:types]) {
		[soundText setStringValue:[[OpenPanel new] filename]];
    }
    return self;
}

- getImage:sender
{
    const char *const types[] = {"tiff", "eps", NULL};  

    if ([[OpenPanel new] runModalForTypes:types]) {
		[imageText setStringValue:[[OpenPanel new] filename]];
    }
    return self;
}

- setSound:sender
{
	if (sounds[num]) [sounds[num] free];
	sounds[num] = [[Sound alloc] initFromSoundfile:[soundText stringValue]];
	if (!sounds[num]) {
		NXRunAlertPanel(NULL, [strings valueForStringKey:"setSfirst"],
				[strings valueForStringKey:"OK"], NULL, NULL);
		return nil;
	}
	alarmType[num] = ALARM_SOUND;
	return self;
}

- setGraphic:sender
{
	if (images[num]) [images[num] free];
	images[num] = [[NXImage alloc] initFromFile:[imageText stringValue]];
	if (!images[num]) {
		NXRunAlertPanel(NULL, [strings valueForStringKey:"setGfirst"],
				[strings valueForStringKey:"OK"], NULL, NULL);
		return nil;
	}
	alarmType[num] = ALARM_GRAPHIC;
	return self;
}

- setSoundAndGraphic:sender
{
	if (!sounds[num])
		sounds[num] =
			[[Sound alloc] initFromSoundfile:[soundText stringValue]];
	if (!images[num])
		images[num] = [[NXImage alloc] initFromFile:[imageText stringValue]];
	if (!sounds[num] && !images[num]) {
		NXRunAlertPanel(NULL, [strings valueForStringKey:"setSandGfirst"],
				[strings valueForStringKey:"OK"], NULL, NULL);
		return nil;
	}
	alarmType[num] = ALARM_SOUND_AND_GRAPHIC;
	return self;
}

- setUnixCommand:sender
{
	[NXApp runModalFor:unixWindow]; // get the command
	alarmType[num] = ALARM_UNIX_COMMAND;
	return self;
}

- gotUnixCommand:sender
{
	if (commands[num]) [commands[num] free];
	commands[num] = [[DAYString alloc] initString:[unixText stringValue]];
	[unixWindow orderOut:self];
	[NXApp stopModal];
	return self;
}

- doAtSetTime:sender
{
	num = 0;
	[typeList setTitle:[strings valueForStringKey:"Sound"]];
	alarmType[num] = -1;
	[[timeMatrix findCellWithTag:1] setIntValue:[absolute minute]];
	[[timeMatrix findCellWithTag:0] setIntValue:[absolute hour]];
	return self;
}

- doFromNow:sender
{
	num = 1;
	[typeList setTitle:[strings valueForStringKey:"Sound"]];
	alarmType[num] = -1;
	[[timeMatrix findCellWithTag:1] setIntValue:[fromSet minute]];
	[[timeMatrix findCellWithTag:0] setIntValue:[fromSet hour]];
	return self;
}

- doFromLaunch:sender
{
	num = 2;
	[typeList setTitle:[strings valueForStringKey:"Sound"]];
	alarmType[num] = -1;
	[[timeMatrix findCellWithTag:1] setIntValue:[fromLaunch minute]];
	[[timeMatrix findCellWithTag:0] setIntValue:[fromLaunch hour]];
	return self;
}

@end
